//**********基本操作*********start*************
var isMac = function () {
    return /macintosh|mac os x/i.test(navigator.userAgent);
}();
/** 是否为windows系统 */
var isWindows = function () {
    return /windows|win32/i.test(navigator.userAgent);
}();

var svgNS = "http://www.w3.org/2000/svg";
var xlinkNS = "http://www.w3.org/1999/xlink";
var workflow = "Process";// id前缀
var _nodeTypeId = {};

var zoom = 1;// 放大倍数***默认为1
var multipleNode = null;// 属性面板选择多个节点
var myFlag = false;

// 右侧属性面板关闭展开
function closepanel(obj) {
    if ($(obj).parent().siblings().is(":hidden")) {
        $(obj).parent().parent().animate({
            "width": "21.4rem"
        });
        $(obj).parent().siblings().fadeIn();
        $(obj).removeClass("icon-menu").addClass("icon-exchange").css({
            "padding": "0.7rem"
        }).parent().css({
            "text-align": "right"
        });
    } else {
        $(obj).parent().parent().animate({
            "width": "2.85rem"
        });
        $(obj).parent().siblings().hide();
        $(obj).removeClass("icon-exchange").addClass("icon-menu").css({
            "padding": "0"
        }).parent().css({
            "text-align": "center"
        });
    }
}

// 工具流面板关闭展开
function closemenu() {
    if ($(".m-icon .u-close i").attr("class") == "icon-exchange") {
        $(".m-icon .u-close i").removeClass("icon-exchange").addClass("icon-menu").css({
            "padding": "0"
        }).parent().css({
            "text-align": "center"
        });
        $(".u-menu .parent").fadeOut();
        $(".u-menu .child li").css("padding", "0.7rem").find("span").fadeOut();
        $(".m-icon").animate({
            "width": "2.85rem"
        });
    } else {
        $(".m-icon .u-close i").removeClass("icon-menu").addClass("icon-exchange").css({
            "padding": "0.85rem"
        }).parent().css({
            "text-align": "right"
        });
        $(".u-menu .parent,.u-menu .child span").fadeIn();
        $(".u-menu .child li").css("padding", "0.7rem 1.4rem 0.7rem 2.85rem").find("span")
        $(".m-icon").animate({
            "width": "21.4rem"
        });
    }
}

// **********基本操作************************

function Designer() {
    this.a = function (g, nodeId, attr) {
        if (Array.isArray(attr))
            $.each(attr, function () {
                if (g.attributes[this])
                    $('#' + nodeId)[0].setAttribute(this, g.attributes[this].textContent);
            });
        else if (g.attributes[attr])
            $('#' + nodeId)[0].setAttribute(attr, g.attributes[attr].textContent);
    }
    /**
     * * 初始化
     */
    this.init = function () {
        this.commonProperty = ["code", "name"];// 所有节点的公共属性
        this.selectedNode = null;
        this.workflowpanel = new WorkflowPanel(this);// 左侧工具流面板
        this.designpanel = new DesignerPanel(this, $(".design"));// 中间设计器面板
        this.propertypanel = new PropertyPanel(this, $("#property"));// 右侧属性面板
        this.toolbar = new ToolBar(this);// 顶部工具栏
        this.load(svgCopy);
        var self = this;
        // 监听键盘删除事件
        $(document).keyup(function(event) {
            if (event.keyCode == 46) {
                self.toolbar.delete();
            }
        });
    };
    this.load = function (svgCopy) {
        var xmldoc = loadXML(svgCopy);
        if (xmldoc == null) return;
        var g = xmldoc.getElementsByTagName("g");
        var nodeId;
        for (var i = 0; i < g.length; i++) {
            switch (g[i].attributes["type"].textContent) {
                case 'start':
                    nodeId = g[i].attributes["id"].textContent;
                    this.selectedNode = defaultNode[0].FlowNode[0];
                    this.designpanel.init(nodeId);
                    $('#' + nodeId + " text textPath").html(g[i].attributes["name"].textContent);
                    this.a(g[i], nodeId, ["code", "name", "transform"]);
                    break;
                case 'end':
                    nodeId = g[i].attributes["id"].textContent;
                    this.selectedNode = defaultNode[0].FlowNode[1];
                    this.designpanel.init(nodeId);
                    $('#' + nodeId + " text textPath").html(g[i].attributes["name"].textContent);
                    this.a(g[i], nodeId, ["code", "name", "transform"]);
                    break;
                case 'draftNode':
                    nodeId = g[i].attributes["id"].textContent;
                    this.selectedNode = defaultNode[1].FlowNode[0];
                    this.designpanel.init(nodeId);
                    $('#' + nodeId + " text textPath").html(g[i].attributes["name"].textContent);
                    this.a(g[i], nodeId, ["code", "name", "operator", "candidate", "candidate_show", "candidategroup", "transform", "notice_way", "attachment", "notice_draft_man", "form_id",
                        "can_update_nodes", "modnodesnames", "must_update_nodes", "mmodnodesnames","form_id","filter_rule", "auto_pick_rule","approval_criteria"]);
                    break;
                case 'approveNode':
                    nodeId = g[i].attributes["id"].textContent;
                    this.selectedNode = defaultNode[1].FlowNode[1];
                    this.designpanel.init(nodeId);
                    $('#' + nodeId + " text textPath").html(g[i].attributes["name"].textContent);
                    this.a(g[i], nodeId, ["code", "name", "transform", "operator", "candidate", "candidate_show", "candidategroup", "communicators", "null_operator_skip", "double_skip",
                        "circulation_mode", "notice_way", "attachment", "options", "remisable_nodes",
                        "remisable_nodesnames", "jumpernodes", "jumpernodesnames", "can_update_nodes", "modnodesnames", "must_update_nodes", "mmodnodesnames",
                        "urge_operator", "notice_draft_man", "auto_skip", "form_id", "filter_rule", "auto_pick_rule","approval_criteria"]);
                    break;
                case 'subFlowNode':
                    nodeId = g[i].attributes["id"].textContent;
                    this.selectedNode = defaultNode[1].FlowNode[2];
                    this.designpanel.init(nodeId);
                    $('#' + nodeId + " text textPath").html(g[i].attributes["name"].textContent);
                    this.a(g[i], nodeId, ["code", "name", "sub_flow", "transform"]);
                    break;
                case 'noticeNode':
                    nodeId = g[i].attributes["id"].textContent;
                    this.selectedNode = defaultNode[1].FlowNode[3];
                    this.designpanel.init(nodeId);
                    $('#' + nodeId + " text textPath").html(g[i].attributes["name"].textContent);
                    this.a(g[i], nodeId, ["code", "name", "transform", "operator", "candidate", "candidate_show", "candidategroup", "notice_way"]);
                    break;
                case 'gatewayex':
                    nodeId = g[i].attributes["id"].textContent;
                    this.selectedNode = defaultNode[2].FlowNode[0];
                    this.designpanel.init(nodeId);
                    this.a(g[i], nodeId, ["code", "name", "transform"]);
                    break;
                case 'gatewaypa':
                    nodeId = g[i].attributes["id"].textContent;
                    this.selectedNode = defaultNode[2].FlowNode[1];
                    this.designpanel.init(nodeId);
                    this.a(g[i], nodeId, ["code", "name", "transform"]);
                    break;
                case 'gatewayin':
                    nodeId = g[i].attributes["id"].textContent;
                    this.selectedNode = defaultNode[2].FlowNode[2];
                    this.designpanel.init(nodeId);
                    this.a(g[i], nodeId, ["code", "name", "transform"]);
                    break;
                default:
                    break;
            }
        }
        for (var i = 0; i < g.length; i++) {
            switch (g[i].attributes["type"].textContent) {
                case 'line':
                    myFlag = true;
                    this.designpanel.nodeinstance = [];
                    this.designpanel.nodeinstance.push($('#' + g[i].attributes["start"].textContent)[0]);
                    this.designpanel.nodeinstance.push($('#' + g[i].attributes["end"].textContent)[0]);
                    this.toolbar.addLine(this.designpanel);
                    nodeId = getLineId(workflow);
                    $('#' + nodeId + " text textPath").html(g[i].attributes["name"].textContent);
                    this.a(g[i], nodeId, ["name", "num", "count", "condition_exps","start_direction","end_direction"]);
                    this.designpanel.nodeinstance = [];
                    //TODO
                    this.designpanel.refreshNodeLine(this.designpanel.nodeData[g[i].attributes["start"].textContent]);
                    myFlag = false;
                    $.each($("#design").find(".selected,._active"), function (index, item) {
                        item.classList.remove("selected", "_active");
                    });
                    break;
                default:
                    break;
            }
        }
    }
}

function getLineId(workflow) {
    var sum = -1;
    $("g[id*='line']").each(function () {
        sum++;
    })
    return workflow + "-line" + sum;
}

// **********工具面板*********start*************
function ToolBar(designer) {
    this.designer = designer;
    var self = this;
    this.delete = function () {
        if(!confirm("确定要删除选中的元素吗？"))return;
        var node_data = self.designer.designpanel.nodeData;
        $("#design ._active").each(function (index, domEle) {
            var line_start = $(domEle).parent().attr("start");
            var line_end = $(domEle).parent().attr("end");
            var startList = node_data[line_start].lineOutList;
            var endtList = node_data[line_end].lineInList;
            startList.splice(jQuery.inArray(line_start, startList), 1);
            endtList.splice(jQuery.inArray(line_end, endtList), 1);
            $(domEle).parent().remove();
        });
        $("#design .selected").each(function (index, domEle) {
            $("#design g").each(function (i, d) {// 同时删除与节点的连线，及nodedata数据
                if (d.getAttribute("start") == domEle.id) {// 节点连出线
                    var list = node_data[d.getAttribute("end")].lineInList;
                    list.splice(jQuery.inArray(domEle.id, list), 1);
                    $(d).remove();
                } else if (d.getAttribute("end") == domEle.id) {// 节点连入线
                    var list = node_data[d.getAttribute("start")].lineOutList;
                    list.splice(jQuery.inArray(domEle.id, list), 1);
                    $(d).remove();
                }
            });
            $(domEle).remove();
        });

    }
    this.buttons = [{// 保存功能
        fonticon: "icon-floppy mergeright",
        tip: "另存为新版本",
        action: function () {
            var begin = new Date();
            zoom = 1;
            document.getElementById("design").setAttribute("viewBox", "0 0 " + 2000 + " " + 2000);
            var svg = $("#svg").html();
            var design = $("#design").html();
            $.each($("#design").find(".selected,._active"), function (index, item) {
                item.classList.remove("selected", "_active");
            });
            var json = {
                "svgString": svg,
                "design": design,
                "name": name,
                "processId": processId,
            };
            var node_msg = "";
            var line_msg = "";
            var approve_msg = "";
            // ***********保存前校验********start*******
            var node_data = self.designer.designpanel.nodeData;// 获取节点数据
            // ***********遍历判断所有的节点连线是否正确**********
            $("#design g").each(function (index) {
                var node_type = this.getAttribute("type");// 节点类型
                if (node_type !== "line") {// 除去连线类型
                    var node_id = this.getAttribute("id");// 节点id***也是节点数据的属性名称
                    var line_in = node_data[node_id].lineInList.length;// 连入线条数量
                    var line_out = node_data[node_id].lineOutList.length;// 连出线条数量
                    if (node_type == "start" && (line_in !== 0 || line_out !== 1)) {// 开始节点****0进1出
                        this.classList.add('f-red');
                        node_msg = "请注意红色节点是否正确接线";
                    } else if (node_type == "end" && (line_in < 1 || line_out !== 0)) {// 结束节点****n进0出
                        this.classList.add('f-red');
                        node_msg = "请注意红色节点是否正确接线";
                    } else if (node_type == "draftNode" || node_type == "noticeNode") {// 起草/通知节点****n进1出
                        if (line_in < 1 || line_out !== 1) {
                            this.classList.add('f-red');
                            node_msg = "请注意红色节点是否正确接线";
                        } else {
                            this.classList.remove('f-red');
                        }
                    } else if (node_type == "gatewayex" && (line_in !== 1 || line_out < 1)) { // 条件分支节点****1进n出
                        this.classList.add('f-red');
                        node_msg = "请注意红色节点是否正确接线";
                    } else if (node_type == "gatewaypa" || node_type == "gatewayin") {// 并行分支/包含分支节点****1进n出或n进1出
                        if ((line_in == 1 && line_out > 0) || (line_in > 0 && line_out == 1)) {
                            this.classList.remove('f-red');
                        } else {
                            this.classList.add('f-red');
                            node_msg = "请注意红色节点是否正确接线";
                        }
                    } else if (node_type == "approveNode") {// 审批节点****n进1出
                        //先判断是否是n进1出
                        if (line_in < 1 || line_out !== 1) {
                            this.classList.add('f-red');
                            node_msg = "请注意红色节点是否正确接线";
                        } else {
                            //再判断属性是否正确***** 1、"处理人"为空。2、"处理人为空跳过"未选中。3、起草节点、审批节点的必须修改的节点全都不包含该节点
                            var approve_id = this.getAttribute("id");// 获取节点ID
                            var person = this.getAttribute("candidate");// 处理人code
                            var value = this.getAttribute("null_operator_skip");// null_operator_skip处理人为空跳过
                            var approve_num = 0;
                            if ((person.length == 0) && (value == "false")) {
                                var $node = $("#design g[type='draftNode'],#design g[type='approveNode']");
                                $node.each(function () {
                                    var must = this.getAttribute("must_update_nodes");// 必须修改的节点
                                    if (must.indexOf(approve_id) == -1) {
                                        approve_num += 1;
                                    } else {
                                        return
                                    }
                                });
                                if (approve_num == $node.size()) {
                                    this.classList.add('f-red');
                                    approve_msg = "请完善红色审批节点的属性信息";
                                } else {
                                    this.classList.remove('f-red');
                                }
                            } else {
                                this.classList.remove('f-red');
                            }
                        }
                    } else if (node_type == "subFlowNode") {// 子流程节点****n进1出
                         var sub_flow = this.getAttribute("sub_flow");
                         if (line_in < 1 || line_out !== 1) {
                             this.classList.add('f-red');
                             node_msg = "请注意红色节点是否正确接线";
                         }
                         if (!sub_flow) {
                             this.classList.add('f-red');
                             node_msg = "请填写子流程编码";
                         } else {
                             var self = this
                             $.ajax({
                                 url : ctxPath + "/validateProcessCode.htm",
                                 data : {
                                     processCode : sub_flow
                                 },
                                 async: false,
                                 dataType : "JSON",
                                 type : "GET",
                                 headers : {
                                     "returntype" : "ajax/json",
                                     "token": getToken()
                                 },
                                 traditional : true,
                                 success : function(data) {
                                     if(!data.data) {
                                         self.classList.add('f-red');
                                         node_msg = "子流程不存在";
                                     }
                                 }
                             });
                         }
                    }
                }
            });
            // ***********遍历判断条件分支、包含分支的连出线表达式******不能为空
            $("#design g[type='line']").each(function () {
                var line_start = this.getAttribute("start");// 获取线条起点的节点id***类型是否为gatewayex或gatewayin
                //条件分支节点
                if (line_start.indexOf("gatewayex") !== -1) {
                    var line_value = this.getAttribute("condition_exps");
                    if (line_value.length == 0) {
                        this.classList.add('f-red-line');
                        line_msg = "请填写红色线条的条件表达式";
                    } else {
                        this.classList.remove('f-red-line');
                    }
                }
                //融合节点
                if (line_start.indexOf("gatewayin") !== -1) {
                    var line_out = node_data[line_start].lineOutList.length;
                    var line_value = this.getAttribute("condition_exps");
                    if (line_out > 1) {//融合节点在首部***条件表达式必填
                        if (line_value.length == 0) {
                            this.classList.add('f-red-line');
                            line_msg = "请填写红色线条的条件表达式";
                        } else {
                            this.classList.remove('f-red-line');
                        }
                    }
                }
            });
            // **********判断是提示错误消息还是提交保存数据*********
            if (node_msg.length > 0) {// 节点连线有错误提示
                setTimeout("alert('"+ node_msg +"');", 500);
            } else if (approve_msg.length > 0) {// 审批节点有错误提示
                setTimeout("alert('"+ approve_msg +"');", 500);
            } else if (line_msg.length > 0) {// 线条属性有错误提示
                setTimeout("alert('"+ line_msg +"');", 500);
            } else {// 提交保存
                var dial = dialog({content: '处理中。。。请稍候'}).showModal();
                $.ajax({
                    type: "POST",
                    url: "workFlowSubmit.htm",
                    data: json,
                    dataType: "json",
                    headers: { "token": getToken()},
                    success: function (message) {
                        dial.close();
                        var end = new Date();
                        var time = end - begin;
                        alert(message.description);
                    },
                    error: function () {
                        dial.close();
                    }
                });
            }
        }
    }, {// 放大功能
        fonticon: "icon-zoom-in mergeright",
        tip: "放大",
        action: function () {
            zoom = zoom / 1.2;
            var viewBox = self.designer.designpanel.container[0].getAttribute("viewBox").split(" ");
            self.designer.designpanel.container[0].setAttribute("viewBox", viewBox[0] + " " + viewBox[1] + " " + 2000 * zoom + " " + 2000 * zoom);
        }
    }, {// 缩小功能
        fonticon: "icon-zoom-out mergeleft",
        tip: "缩小",
        action: function () {
            var viewBox = self.designer.designpanel.container[0].getAttribute("viewBox").split(" ");
            zoom = zoom * 1.2;
            self.designer.designpanel.container[0].setAttribute("viewBox", viewBox[0] + " " + viewBox[1] + " " + 2000 * zoom + " " + 2000 * zoom);
        }
    }, {// 恢复原始大小
        fonticon: "icon-window-restore",
        tip: "恢复",
        action: function () {
            zoom = 1;
            document.getElementById("design").setAttribute("viewBox", "0 0 " + 2000 + " " + 2000);
        }
    }, {// 给节点添加连线
        fonticon: "icon-flow-line",
        tip: "添加连线",
        action: this.addLine
    }, {// 移动整个设计器中的所有节点
        fonticon: "icon-move",
        tip: "移动屏幕",
        action: function () {
            designer.designpanel.move = designer.designpanel.move ^ 1;
        }
    }, {
        fonticon: "icon-copy2",
        tip: "复制",
        action: function () {
        },
        init: function (btn) {
            new Clipboard(btn, {
                text: function (trigger) {
                    return $("#svg").html();
                }
            }).on("success", function (e) {
                top.dialog({
                    content: "内容已复制到剪贴板.",
                    quickClose: true
                }).show();
            });
        }
    }, {
        fonticon: "icon-paste",
        tip: "粘贴",
        action: function () {
            top.dialog({
                content: "<span style=\"color:red\">请把复制的内容填入</span><br/><textarea id=\"__content\" cols=\"80\" rows=\"10\"></textarea>",
                okValue: "确定",
                ok: function () {
                    self.designer.load($("#__content").val());
                    this.close().remove();
                },
                cancelValue: "取消",
                cancel: function () {
                    this.remove().remove();
                }
            }).show();
// self.designer.load();
        }
    }, {// 删除选中节点
        fonticon: "icon-cancel-1",
        tip: "删除",
        action: this.delete
    }, {// 退出
        fonticon: "icon-off",
        tip: "退出",
        action: function () {
            if (confirm("请确认流程是否已保存，退出选择是，取消选否")) {
                opener.reload();
                window.close();
            }
        }
    }];
    this.tools = [{
        svg: "<svg width='20' height='20' viewBox='0 0 20 20' class='icon'> <use xlink:href='#vertical' /></svg>",
        action: function(designer) {
            if (designer.nodeinstance.length < 1) {
                return
            }
            // 第一项
            var target = designer.nodeinstance[0];
            var viewBox = designer.container[0].getAttribute("viewBox").split(" ");
            var matrix = target.getCTM();
            var e = matrix.e * zoom;
            var f = matrix.f * zoom;
            $(designer.nodeinstance).each(function(){
                var matrix1 = this.getCTM();
                var a1 = matrix1.a * zoom;
                var d1 = matrix1.d * zoom;
                this.setAttribute("transform", "matrix(" + a1 + ",0,0," + d1 + "," + e + "," + f + ")");
                designer.refreshNodeLine(designer.nodeData[this.id]);
                e += 300 / zoom
            })
        }
    },{
        svg: "<svg width='20' height='20' viewBox='0 0 20 20' class='icon'> <use xlink:href='#horizon' /></svg>",
        action: function(designer) {
            if (designer.nodeinstance.length < 1) {
                return
            }
            // 第一项
            var target = designer.nodeinstance[0];
            var viewBox = designer.container[0].getAttribute("viewBox").split(" ");
            var matrix = target.getCTM();
            var e = matrix.e * zoom;
            var f = matrix.f * zoom;
            $(designer.nodeinstance).each(function(){
                var matrix1 = this.getCTM();
                var a1 = matrix1.a * zoom;
                var d1 = matrix1.d * zoom;
                var flag = this.getAttribute("type").indexOf("gateway") >= 0
                this.setAttribute("transform", "matrix(" + a1 + ",0,0," + d1 + "," + (flag ? e+70.5 : e) + "," + f + ")");
                designer.refreshNodeLine(designer.nodeData[this.id]);
                f += 160
            })
        }
    }];
    // 初始化
    this.init = function (selector) {
        $.each(this.buttons, function () {
            var self2 = this;
            var item = $("<i>").addClass(this.fonticon).attr("title", this.tip);
            this.init && this.init(item[0]);
            if (this.action)
                item.on("click", function () {
                    self2.action((self.designer.designpanel));
                });
            selector.append(item);
        });
        $.each(this.tools, function () {
            var self2 = this;
            var item = $(this.svg);
            this.init && this.init(item[0]);
            if (this.action)
                item.on("click", function () {
                    self2.action((self.designer.designpanel));
                });
            selector.find(".textalign").append(item);
        });
    }
}

ToolBar.prototype = {
    // 连线
    addLine: function (designer) {
        var self = this;
        var source = designer.nodeinstance[0];
        var target = designer.nodeinstance[designer.nodeinstance.length - 1];
        var fixedSource = 1;// 按顺序
        if (source.getAttribute("id").startsWith(workflow + "-gateway")) {
            fixedSource = 2;// 定头
        } else if (target.getAttribute("id").startsWith(workflow + "-gateway")) {
            fixedSource = 4;// 定尾
        }
        $(designer.nodeinstance).each(function (index) {
            if (index == 0 && fixedSource != 4)
                return true;
            if (fixedSource == 4 && index == designer.nodeinstance.length - 1)
                return true;
            if ((fixedSource & 3) != 0)
                target = this;
            else
                source = this;
            var lineFlag;
            $("g[id*='line']").each(function (i, d) {
                if (d.getAttribute("start") == source.id && d.getAttribute("end") == target.id) {
                    lineFlag = false;
                    return;
                }
            });
            if (lineFlag == false) {
                alert(source.id + "," + target.id + "之间不能重复画线!");
                return;
            }
            var line = new Line(source, target, designer).refresh();
            designer.nodeData[source.id].lineOutList.push(target);
            designer.nodeData[target.id].lineInList.push(source);
            designer.nodeData[source.id].lines.push(line);
            designer.nodeData[target.id].lines.push(line);
            if (fixedSource == 1)
                source = target;
        });
    }
}

// **********工作流面板*********start***********
function WorkflowPanel(designer) {
    this.designer = designer;
    var self = this;
    this.tree = defaultNode;
    // 初始化
    this.init = function (selector) {
        $.each(this.tree, function () {// 遍历多少种类型
            var parent = $("<div>").addClass("parent").append($("<i>").addClass("fa").addClass('icon-down-open'));
            parent.append(this.text);
            var ul = $('<ul class="child"></ul>');
            $.each(this.FlowNode, function (index) {// 遍历工作流节点
                for (var i = index; i <= index; i++) {
                    var li = $('<li type="' + this.type + '"><svg width="16" height="16" viewBox="0 0 16 16"><use xlink:href="#' + this.icon
                        + 'Icon" /></svg><span>' + this.name + '</span></li>');
                    ul.append(li);
                    var data = this;
                    li.click(function () {
                        $(".m-icon .child li").removeClass("active");
                        $(this).addClass("active");
                        self.designer.selectedNode = data;
                    });
                }
            });
            var tmp = $("<li>").append(parent).append(ul);
            parent.click(function () {
                $(this).siblings().slideToggle();
                $(this).find(".fa").toggleClass('icon-right-open')
            });
            selector.append(tmp);
        });
    }
}

// **********设计器面板*********start*************
function DesignerPanel(designer, container) {
    this.designer = designer;
    this.container = container;// jquery
    this.nodeinstance = [];// 节点实例数组
    this.drag = false;
    this.move = 0;
    this.nodeData = {};// 节点，数据映射数据,key为g节点的ID,value为对应的数据
    this.startPos = [];
    this.lastPos = [];
    this.offset = {};
    this.offsetY = function () {
        return this.container[0].getClientRects()[0].top;
    };
    this.offsetX = function () {
        return this.container[0].getClientRects()[0].left;
    };
    var self = this;

    container.on({
        click: function (event) {
            if (self.designer.selectedNode) {
                var selectData = self.designer.selectedNode;
                var type = selectData.type;// 获取节点类型
                // 判断公共属性是否已经加入属性列表中
                if (selectData.property[0] != "id") {
                    var tempArr = designer.commonProperty.concat(self.designer.selectedNode.property);// 把公共属性添加到属性列表中
                    var resultArr = []
                    for (var i = 0; i < tempArr.length; i++) {
                        if (resultArr.indexOf(tempArr[i])<0) {
                            resultArr.push(tempArr[i])
                        }
                    }
                    selectData.property = resultArr
                }
                var props = selectData.property;
                var nodeId = self.getId(type, workflow);// 获取id
                var inst = {};
                // 开始只能有一个
                switch (selectData.type) {
                    case "start":
                        var id = $("#design").find(".selectable[type='start']").attr("id");
                        if (id == undefined) {
                            inst = selectData.inst(event.offsetX * zoom, event.offsetY * zoom, self, nodeId, props);
                            self.nodeData[inst.svg.id] = inst;
                            inst.property = self.setProp(props);
                        } else if (id.match("start") == "start") {
                            alert("只能添加一个开始节点。");
                        } else {
                            inst = selectData.inst(event.offsetX * zoom, event.offsetY * zoom, self, nodeId, props);
                            self.nodeData[inst.svg.id] = inst;
                            inst.property = self.setProp(props);
                        }
                        break;
                    case "end":
                        var id = $("#design").find(".selectable[type='end']").attr("id");
                        if (id == undefined) {
                            inst = selectData.inst(event.offsetX * zoom, event.offsetY * zoom, self, nodeId, props);
                            self.nodeData[inst.svg.id] = inst;
                            inst.property = self.setProp(props);
                        } else if (id.match("end") == "end") {
                            alert("只能添加一个结束节点。");
                        } else {
                            inst = selectData.inst(event.offsetX * zoom, event.offsetY * zoom, self, nodeId, props);
                            self.nodeData[inst.svg.id] = inst;
                            inst.property = self.setProp(props);
                        }
                        break;
                    default:
                        inst = selectData.inst(event.offsetX * zoom, event.offsetY * zoom, self, nodeId, props);
                        self.nodeData[inst.svg.id] = inst;
                        inst.property = self.setProp(props);
                        break;
                }
                $(inst.svg).mousedown(function (event) {
                    self.elementClick(event, this, selectData, inst, nodeId);
                });
                self.designer.selectedNode = null;
            }
        },
        mousedown: function (event) {
            self.drag = true;
            //TODO
            // self.container.find("selectable").each(function () {
            //     console.log(this);
            // });

            self.lastPos = [event.offsetX, event.offsetY];
        },
        mouseup: function (event) {
            self.drag = false;
            self.lastPos = null;
        },
        mouseout: function (event) {
        },
        mouseenter: function (event) {
            if (event.target.tagname == 'svg') {
                self.drag = false;
                self.lastPos = null;
            }
        },
        mousemove: function (event) {
            if (self.drag) {
                var offset = [event.offsetX - self.lastPos[0], event.offsetY - self.lastPos[1]];
                if (self.move == 1) {
                    var viewBox = self.container[0].getAttribute("viewBox").split(" ");
                    viewBox[0] = viewBox[0] - offset[0];
                    viewBox[1] = viewBox[1] - offset[1];
                    self.container[0].setAttribute("viewBox", viewBox.join(" "));
                } else {
                    $.each(self.nodeinstance, function () {
                        var viewBox = self.container[0].getAttribute("viewBox").split(" ");
                        var matrix = this.getCTM();
                        var a = matrix.a * zoom;
                        var d = matrix.d * zoom;
                        var e = matrix.e * zoom + offset[0] * zoom + Number(viewBox[0]);
                        var f = matrix.f * zoom + offset[1] * zoom + Number(viewBox[1]);
                        this.setAttribute("transform", "matrix(" + a + ",0,0," + d + "," + e + "," + f + ")");
                        self.refreshNodeLine(self.nodeData[this.id]);
                    });
                }
                self.lastPos = [event.offsetX, event.offsetY];
            }
        }
    });
};
DesignerPanel.prototype = {
    init: function (nodeId) {
        var self = this;
        if (this.designer.selectedNode) {
            var selectData = this.designer.selectedNode;
            var type = selectData.type;// 获取节点类型
            // 判断公共属性是否已经加入属性列表中
            if (selectData.property[0] != "id") {
                var tempArr = designer.commonProperty.concat(this.designer.selectedNode.property);// 把公共属性添加到属性列表中
                var resultArr = []
                for (var i = 0; i < tempArr.length; i++) {
                    if (resultArr.indexOf(tempArr[i])<0) {
                        resultArr.push(tempArr[i])
                    }
                }
                selectData.property = resultArr
            }
            var props = selectData.property;
            // var nodeId = this.getId(type, workflow);// 获取id
            var inst = {};
            // 开始只能有一个
            switch (selectData.type) {
                case "start":
                    var id = $("#design").find(".selectable").attr("id");
                    if (id == undefined) {
                        inst = selectData.inst(1 * zoom, 1 * zoom, this, nodeId, props);
                        this.nodeData[inst.svg.id] = inst;
                        inst.property = this.setProp(props);
                    } else if (id.match("start") == "start") {
                        alert("只能添加一个开始节点哦！");
                    } else {
                        inst = selectData.inst(1 * zoom, 1 * zoom, this, nodeId, props);
                        this.nodeData[inst.svg.id] = inst;
                        inst.property = this.setProp(props);
                    }
                    break;
                default:
                    inst = selectData.inst(1 * zoom, 1 * zoom, this, nodeId, props);
                    this.nodeData[inst.svg.id] = inst;
                    inst.property = this.setProp(props);
                    break;
            }
            $(inst.svg).mousedown(function (event) {
                self.elementClick(event, this, selectData, inst, nodeId);
            });
            this.designer.selectedNode = null;
        }
    },

    // 更新连线
    refreshNodeLine: function (node) {
        $.each(node.lines, function () {
            this.refresh();
        });
    },
    // 点击选中节点实例
    elementClick: function (event, element, data, instRet, nodeId) {
        if (myFlag == true) {
            this.nodeinstance.push(element);
            return;
        }
        if (multipleNode) {// 如果点击了添加节点的按钮
            multipleNode(nodeId);
        } else {// 选中节点展示节点属性
            if ((isMac && !event.metaKey) || (isWindows && !event.ctrlKey)) {
                $.each(this.container.find(".selected,._active"), function (index, item) {
                    item.classList.remove("selected", "_active");
                });
                this.nodeinstance.splice(0, this.nodeinstance.length);
            }
            if (element.classList.contains("selected")) {
                element.classList.remove("selected");
                this.nodeinstance.splice(this.nodeinstance.indexOf(element), 1);
            } else {
                element.classList.add("selected");
                this.nodeinstance.push(element);
            }

            this.designer.propertypanel.init(data, nodeId);
            $(".content").eq(0).show();// 第一个默认显示
            $(".u-property [data-toggle='title']").eq(0).addClass("icon-minus");// 第一个默认显示
        }
    },
    // 创建节点
    addNode: function (nodeType, attrs) {
        var node = document.createElementNS(svgNS, nodeType);
        if (attrs) {
            $.each(attrs, function (key, value) {
                node.setAttribute(key, value);
            });
        }
        return node;
    },
    // 获取id
    getId: function (nodeType, workflow) {
        if (!_nodeTypeId[nodeType])
            _nodeTypeId[nodeType] = 0;
        while (this.container.find("#" + workflow + "-" + nodeType + _nodeTypeId[nodeType]).length > 0) { // 如果节点存在加1
            _nodeTypeId[nodeType]++;
        }
        return workflow + "-" + nodeType + (_nodeTypeId[nodeType]++);
    },
    // 生成属性键值对
    setProp: function (prop) {
        var property = {};
        $.each(prop, function (index) {
            var key = prop[index];
            // if(index=2){property[key]=}
            // else
            property[key] = "No value";
        });
        return property;
    }
}

// **********属性面板*********start*************
function PropertyPanel(designer, container) {
    this.designer = designer;
    this.container = container;
    this.defaultProp = {
        id: {name: "ID", inputname: "id", eventname: ""},
        code: {name: "节点编号", inputname: "code", eventname: "code"},
        name: {name: "名称", inputname: "", eventname: "name"},
        start_direction: {name: "开始方向", inputname: "", eventname: "start_direction"},
        end_direction: {name: "结束方向", inputname: "", eventname: "end_direction"},
        form_id: {name: "表单编号", inputname: "form_id", eventname: "form_id"},
        sub_flow: {name: "子流程", inputname: "sub_flow", eventname: "sub_flow"},
        notice_way: {name: "通知方式", inputname: "notice_way", eventname: "notice_way"},
        attachment: {name: "允许上传附件", inputname: "attachment", eventname: "attachment"},
        notice_draft_man: {name: "通知起草人", inputname: "notice_draft_man", eventname: "notice_draft_man"},
        remisable_nodes: {name: "可驳回的节点", inputname: "", eventname: ""},
        modnodesnames: {name: "允许变更审批人的节点", inputname: "modnodesnames", eventname: ""},
        mmodnodesnames: {name: "必须变更审批人的节点", inputname: "mmodnodesnames", eventname: ""},
        operator: {name: "默认处理人", inputname: "", eventname: ""},
        null_operator_skip: {name: "处理人为空跳过", inputname: "null_operator_skip", eventname: "null_operator_skip"},
        double_skip: {name: "身份重复跳过", inputname: "double_skip", eventname: "double_skip"},
        circulation_mode: {name: "流转方式", inputname: "circulation_mode", eventname: "circulation_mode"},
        filter_rule: {name: "过滤规则", inputname: "filter_rule", eventname: "filter_rule"},
        auto_pick_rule: {name: "自动选人规则", inputname: "自动选人规则", eventname: "auto_pick_rule"},
        approval_criteria: {name: "审批基准", inputname: "审批基准", eventname: "approval_criteria"},
        options: {name: "操作类型", inputname: "options", eventname: "options"},
        urge_operator: {name: "催办处理人", inputname: "urge_operator", eventname: "urge_operator"},
        candidate: {name: "处理人", inputname: "candidate", eventname: ""},
        auto_skip: {name: "自动跳过", inputname: "auto_skip", eventname: "auto_skip"},
        condition_exps: {name: "条件表达式", inputname: "condition_exps", eventname: "condition_exps"},
        count: {name: "顺序", inputname: "count", eventname: "auto_skip"},
        communicators: {name: "沟通人", inputname: "", eventname: ""},
        jumpernodes: {name: "可跳转的节点", inputname: "", eventname: ""}
    };
    this.group = [
        {
            "group": "基本属性",
            "property": ["id", "code", "name", "form_id", "sub_flow",  "notice_way", "options", "attachment", "circulation_mode", "null_operator_skip", "double_skip", "condition_exps", "count", "start_direction", "end_direction"] // ID,名称,表单ID
        },
        {
            "group": "处理人属性",
            "property": ["filter_rule", "auto_pick_rule","approval_criteria","candidate"]
        },
        {
            "group": "权限属性",
            "property": [
                "modnodesnames", "mmodnodesnames"]
        },
        {
            "group": "高级属性",
            "property": [
                "notice_draft_man", "urge_operator", "auto_skip"]
        }];
}

PropertyPanel.prototype.timelayout = function (parent, nodeId, param, data, index) {
    selcetString = '#' + nodeId;
    var str = $('#' + nodeId).attr(param);
    if (str) {
        var array = str.split(",");
        $.each(["天", "时", "分"], function (idx, value) {
            var input1 = $("<input>").attr({
                id: nodeId + data.id + index + "i" + (idx + 1),
                value: array[idx],
                maxLength: 2,
                type: "number",
                style: "width:35px"
            });
            parent.append(input1);
            parent.append(value);
        });
    }
}
PropertyPanel.prototype.checkboxlayout = function (parent, nodeId, param, data, index, prefix, array) {
    var str = $('#' + nodeId).attr(param);
    var strarray = str.split(",");
    $.each(array, function (idx, val) {
        var checkbox = $("<input>").attr({
            id: nodeId + data.id + index + prefix + (idx + 1),
            type: 'checkbox'
        });
        if (strarray[idx] == "true")
            checkbox.attr("checked", true);
        if (idx == 3) {
            parent.append("<br/>")
        }
        parent.append($("<label>").append(checkbox).append(val));
    });
}

PropertyPanel.prototype.selectlayout = function (parent, nodeId, param, data, index, prefix, map) {
    var str = $('#' + nodeId).attr(param);
    var select = $("<select>").attr({
        id: nodeId + data.id + index + prefix
    });
    parent.append(select);
    $.each(map, function (k, v) {
        var option = $("<option>").attr("value", k).text(v);
        if (str == k)
            option.attr("selected", "selected");
        select.append(option);
    });
}
/**
 * parent div容器 param 参数 nodeId 节点标识
 */
PropertyPanel.prototype.inputlayout = function (parent, nodeId, param, data, index, url) {
    var valueString = $('#' + nodeId).attr(param)
    if(param == "code" && !$('#' + nodeId).attr(param)) {
        valueString = $('#' + nodeId).attr("id")
    }
    if(param == "condition_exps"){
        valueString = valueString.replace(/&lt;/g, "<");
        valueString = valueString.replace(/&lt;/g, ">");
        valueString = valueString.replace(/&#39;/g, "'");
        valueString = valueString.replace(/&quot;/g, "\"");
    }
    var value = $("<input>").attr({
        id: nodeId + data.id + index,
        type: 'text',
        value: valueString
    });
    parent.append(value);
    if (url)// 如果有url值，添加自动完成功能
    {
        value.val($('#' + nodeId).attr(param + "_show"));
        var tmp_name = ($('#' + nodeId).attr(param + "_show") || "").split(",");
        var tmp = ($('#' + nodeId).attr(param) || "").split(",");
        var _codes = [];
        for (var i = 0; i < tmp.length; i++) {
            if (tmp[i] == "")
                continue;
            var tmp_code = tmp[i].split("-");
            var _tmp_item = {
                name: tmp_name[i],
                type: tmp_code[0],
                code: tmp_code[1]
            };
            _codes.push(_tmp_item);
        }
        value.data("staff-code", _codes);
        value.focus(function () {
            $(this).staffSelector({
                type: 31,
                checkType: "multi",
                data: $(this).data("staff-code"),
                process: function (data) {
                    $('#' + nodeId).attr(param, $(data).map(function () {
                        return this.type + "-" + this.code;
                    }).get().join(","));
                    $('#' + nodeId).attr(param + "_show", $(data).map(function () {
                        return this.name;
                    }).get().join(","));
                }
            });
        });
    }
}
PropertyPanel.prototype.event = function (evt, attr, input, nodeId, func) {
    input.off(evt).on(evt, function () {
        var value = "";
        input.each(function () {
            if ($(this).attr("type") == "checkbox")
                value += ($(this).is(":checked") ? "true" : "false") + ",";
            else
                value += $(this).val() + ",";
        });
        value = value.replace(/</g, "&lt;");
        value = value.replace(/>/g, "&gt;");
        value = value.replace(/\'/g, "&#39;");
        value = value.replace(/\"/g, "&quot;");
        if (value.endsWith(","))
            value = value.substring(0, value.length - 1);
        $('#' + nodeId).attr(attr, value);
        if (func)
            func(value);
    });
}

PropertyPanel.prototype.init = function (data, nodeId) {
    // 属性面板生成属性
    this.container.empty();
    var self = this;
    var map = {};// 存储每个分组的位置
    var element = [];// 存每个分组的元素
    $.each(this.group, function (index) {
        var group = $("<div class=\"u-property-title icon-plus\" data-toggle=\"title\">" + this.group + "</div>");
        self.container.append(group);
        element.push(group);
        $.each(this.property, function () {
            map[this] = index;
        });
    });
    $.each(element, function () {
        var panel = $("<div>").addClass("content").addClass("active").css("height", "calc(100% - " + (34 * element.length) + "px)");
        this.after(panel);
    });
    $.each(data.property, function (index, val) {
        var selcetString;
        var info = $("<div>").addClass("info");
        var text = $("<label>").addClass("info-name").attr({
            "title": "",
            "for": nodeId + data.id + index
        }).text(self.defaultProp[val].name);
        var divValue = $("<div>").addClass("info-value").attr("title", "");
        switch (val) {
            // 文本输入框
            case "id": // ID
                selcetString = '#' + nodeId;
                valueString = $(selcetString).attr('id');
                divValue = $("<div>").addClass("info-value").text(valueString);
                var value = "";
                break;
            case "code": // 节点编号
                self.inputlayout(divValue, nodeId, val, data, index);
                break;
            case "name": // 名称
                selcetString = '#' + nodeId + " text textPath";
                var valueString = $(selcetString).html();
                var value = $("<input>").attr({
                    id: nodeId + data.id + index,
                    type: 'text',
                    value: valueString
                });
                divValue.append(value);
                break;
            case "start_direction":
            case "end_direction": // 操作定义
                self.selectlayout(divValue, nodeId, val, data, index, "", {
                    "0": "自动",
                    "top": "上",
                    "right": "右",
                    "bottom": "下",
                    "left": "左"
                });
                break;
            case "notice_way": // 通知方式
                self.checkboxlayout(divValue, nodeId, val, data, index, "c", ["待办", "邮件", "短信"]);
                break;
            case "attachment": // 审批意见中上传附件
            case "double_skip": // 身份重复跳过
            case "null_operator_skip": // 处理人为空跳过
                self.checkboxlayout(divValue, nodeId, val, data, index, "", [""]);
                break;
            case "notice_draft_man": // 通知起草人
            case "urge_operator": // 催办处理人
            case "auto_skip": // 自动跳过
                self.timelayout(divValue, nodeId, val, data, index);
                break;
            case "form_id": // 表单ID
            case "sub_flow": // 子流程
            case "modnodesnames": // 可修改的节点
            case "mmodnodesnames": // 必须修改的节点
            case "condition_exps":// 条件表达式********融合网关、排他网关连线属性
            case "count":// 顺序*********融合网关连线属性
                self.inputlayout(divValue, nodeId, val, data, index);
                break;
            case "candidate": // 处理人
                var value = self.inputlayout(divValue, nodeId, val, data, index, "/staffdepartmentquery.htm");
                break;
            case "circulation_mode": // 流转方式
                self.selectlayout(divValue, nodeId, val, data, index, "", {
                    "1": "并行",
                    "2": "串行",
                    "3": "会审"
                });
                break;
            case "options": // 自定义操作
                self.checkboxlayout(divValue, nodeId, val, data, index, "c", ["驳回", "转办", "沟通", "催办", "废弃"]);
                break;
            case "filter_rule": // 过滤规则
                self.selectlayout(divValue, nodeId, val, data, index, "", {
                    "0": "无",
                    "1": "只选择本部门及子部门审核人",
                    "2": "不选择本部门及子部门审核人",
                    "3": "不选择制单人",
                    "4": "只选择上级部门审核人",
                    "5": "只选择本部门及上级部门审核人",
                    "6": "只选择下级部门审核人",
                    "7": "只选择一级部门审核人"
                });
                break;
            case "auto_pick_rule": // 自动选人规则
                self.selectlayout(divValue, nodeId, val, data, index, "", {
                    "0": "无",
                    "1": "发起人",
                    "2": "直属上司"
                });
                break;
            case "approval_criteria": //审批基准
                self.selectlayout(divValue, nodeId, val, data, index, "", {
                    "1": "以制单人为准",
                    "2": "以当前审批人为准"
                });
                break;
            default:
                break;
        }
        info.append(text, divValue);
        if (map[data.property[index]] != null)
            element[map[data.property[index]]].next().append(info);
        else
            element[element.length - 1].next().append(info);

        var selectID = '#' + nodeId + data.id + index;
        // 事件处理
        var propText = data.property[index];
        var eventName = self.defaultProp[propText].eventname;
        switch (propText) {
            case "name": // 名称
                self.event("change", eventName, $(selectID), nodeId, function (val) {
                    $('#' + nodeId + " text textPath").html(val);
                });
                break;
            case "notice_way": // 通知方式
                self.event("change", eventName, $("#" + nodeId + data.id + index + "c1,#" + nodeId + data.id + index + "c2,#" + nodeId + data.id + index + "c3"),
                    nodeId);
                break;
            case "notice_draft_man": // 通知起草人
                self.event("change", eventName, $("#" + nodeId + data.id + index + "i1,#" + nodeId + data.id + index + "i2,#" + nodeId + data.id + index
                    + "i3"), nodeId);
                break;
            case "attachment": // 审批意见中上传附件
            case "double_skip": // 身份重复跳过
            case "null_operator_skip": // 处理人为空跳过
                self.event("change", eventName, $(selectID + "1"), nodeId);
                break;
            case "condition_exps": // 条件表达式**********融合网关、排他网关连线属性
            case "code":
            case "form_id": // 表单ID
            case "sub_flow":
            case "circulation_mode": // 流转方式
            case "filter_rule": // 流转方式
            case "auto_pick_rule": // 流转方式
            case "approval_criteria": //审批基准
            case "start_direction"://线条开始的方向
            case "end_direction"://线条结束的方向
                self.event("change", eventName, $(selectID), nodeId);
                break;
            case "options": // 自定义操作
                var c1 = nodeId + data.id + index + 'c1';
                var c2 = nodeId + data.id + index + 'c2';
                var c3 = nodeId + data.id + index + 'c3';
                var c4 = nodeId + data.id + index + 'c4';
                var c5 = nodeId + data.id + index + 'c5';
                self.event("change", eventName, $("#" + c1 + ",#" + c2 + ",#" + c3 + ",#" + c4 + ",#" + c5), nodeId);
                break;
            case "urge_operator": // 催办处理人
            case "auto_skip": // 自动跳过
                var i1 = nodeId + data.id + index + 'i1';
                var i2 = nodeId + data.id + index + 'i2';
                var i3 = nodeId + data.id + index + 'i3';
                self.event("change", eventName, $("#" + i1 + ",#" + i2 + ",#" + i3), nodeId);
                break;
            case "candidate":// 处理人----
                break;
            case "count": // 顺序
                self.event("change", "auto_skip", $(selectID), nodeId);
                break;
            case "modnodesnames": // 可修改的节点
                $(selectID).removeAttr("onclick").bind(
                    "click",
                    function () {
                        var select = $("<select>").attr({
                            id: "multipleSelect",
                            multiple: "multiple",
                            size: "10"
                        }).css({
                            width: "100%",
                            height: "90%"
                        });
                        var data = $('#' + nodeId).attr('can_update_nodes');
                        data = ',' + data + ','
                        $('#design g').each(
                            function (i, d) {
                                if (d.getAttribute("id") == nodeId)
                                    return;
                                if (d.getAttribute("type") == "approveNode" || d.getAttribute("type") == "draftNode") {
                                    if (data.indexOf(',' + d.getAttribute("id") + ',') !== -1) {
                                        var option = "<option selected value='" + d.getAttribute("id") + "'>" + d.getAttribute("id")
                                            + d.getAttribute("name") + "</option>";
                                    } else {
                                        var option = "<option value='" + d.getAttribute("id") + "'>" + d.getAttribute("id") + d.getAttribute("name")
                                            + "</option>";
                                    }
                                    option = "<option value=''>无</option>" + option
                                    select.append(option);
                                }
                            });
                        dialog({
                            width: 335,
                            height: 400,
                            content: select[0],
                            button: [{
                                value: "确定",
                                callback: function () {
                                    var arr = [];
                                    $("#multipleSelect option:selected").each(function () {
                                        if ($(this).text() != "无"){
                                            arr.push($(this).text())
                                        }
                                    });
                                    // *******可修改节点和必须修改节点*********不能重复
                                    var must = $('#' + nodeId).attr('must_update_nodes');// 获取必须修改节点填入的节点id
                                    if ($("#multipleSelect").val() == must && must) {
                                        alert("可修改节点和必须修改节点不能重复");
                                    } else {
                                        $(selectID).val(arr);
                                        $('#' + nodeId).attr('can_update_nodes', $("#multipleSelect").val() || "");
                                        $('#' + nodeId).attr('MODNodesnames', arr);
                                    }
                                    this.close().remove();
                                }
                            }]
                        }).showModal();
                    });
                break;
            case "mmodnodesnames": // 必须修改的节点
                $(selectID).removeAttr("onclick").bind(
                    "click",
                    function () {
                        var select = $("<select>").attr({
                            id: "multipleSelect",
                            multiple: "multiple",
                            size: "10"
                        }).css({
                            width: "100%",
                            height: "90%"
                        });
                        var data = $('#' + nodeId).attr('must_update_nodes');
                        data = ',' + data + ','
                        $('#design g').each(
                            function (i, d) {
                                if (d.getAttribute("id") == nodeId)
                                    return;
                                if (d.getAttribute("type") == "approveNode" || d.getAttribute("type") == "draftNode") {
                                    if (data.indexOf(',' + d.getAttribute("id") + ',') !== -1) {
                                        var option = "<option selected value='" + d.getAttribute("id") + "'>" + d.getAttribute("id")
                                            + d.getAttribute("name") + "</option>";
                                    } else {
                                        var option = "<option value='" + d.getAttribute("id") + "'>" + d.getAttribute("id") + d.getAttribute("name")
                                            + "</option>";
                                    }
                                    option = "<option value=''>无</option>" + option
                                    select.append(option);
                                }
                            });
                        dialog({
                            content: select[0],
                            width: 335,
                            height: 400,
                            button: [{
                                value: "确定",
                                callback: function () {
                                    var arr = [];
                                    $("#multipleSelect option:selected").each(function () {
                                        if ($(this).text() != "无"){
                                            arr.push($(this).text())
                                        }
                                    });
                                    // *******必须修改节点和可修改节点*********不能重复
                                    var can = $('#' + nodeId).attr('can_update_nodes');// 获取可修改节点填入的节点id
                                    if ($("#multipleSelect").val() == can && can) {
                                        alert("必须修改节点和可修改节点不能重复");
                                    } else {
                                        $(selectID).val(arr);
                                        $('#' + nodeId).attr('must_update_nodes', $("#multipleSelect").val() || "");
                                        $('#' + nodeId).attr('MMODNodesnames', arr);
                                        this.close().remove();
                                    }
                                }
                            }]
                        }).showModal();
                    });
                break;
            default:
                break;
        }
    });
}
// **********默认属性***********start*************
var defaultNode = [
    {
        text: "Start/End Events",
        FlowNode: [
            {
                name: "开始（Start）",
                id: "start",
                type: "start",
                icon: "start",
                width: 201,
                height: 60,
                caption: "开始",
                property: [],
                inst: function (x, y, panel, nodeId) {
                    var container = panel.container;
                    var rect = panel.addNode("rect", {
                        x: "1",
                        y: "1",
                        rx: "30",
                        ry: "30",
                        width: 200,
                        height: 60,
                        "fill": "#fff"
                    });
                    // 线条及文字
                    var line = panel.addNode("path", {
                        "stroke-width": 1,
                        fill: "none",
                        d: "M0 30L200 30",
                        r: 30,
                        id: nodeId + 'l',
                        "stroke": "none"
                    });
                    var txt = panel.addNode("text");
                    var txtPath = panel.addNode("textPath", {
                        "text-anchor": "middle",
                        "baseline-shift": "-4",
                        "startOffset": "50%",
                        "fill": "#000",
                        "stroke": "none"
                    });
                    txtPath.setAttributeNS(xlinkNS, "xlink:href", "#" + nodeId + "l");
                    txtPath.textContent = "开始";
                    txt.appendChild(txtPath);
                    // 包裹
                    var g = panel.addNode("g", {
                        transform: 'matrix(1,0,0,1,' + x + ',' + y + ')',
                        class: "selectable",
                        id: nodeId,
                        name: "开始",
                        code: nodeId,
                        type: "start"
                    });
                    $(g).append(rect, line, txt);
                    var iconSvg = '<svg y="16" x="16" stroke="none"  width="28" height="28" viewBox="0 0 16 16"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#startIcon"></use></svg>'
                    $(iconSvg).appendTo($(g));
                    container.append(g);
                    var ret = {
                        name: "开始",
                        id: "startIns",
                        svg: g,
                        property: {},
                        lineInList: [],
                        lineOutList: [],
                        lines: [],
                        text: "开始",
                        x: x,
                        y: y,
                        original: this
                    };
                    return ret;
                }
            },
            {
                name: "结束（End）",
                id: "end",
                type: "end",
                icon: "end",
                width: 201,
                height: 60,
                caption: "结束",
                property: [],
                inst: function (x, y, panel, nodeId) {
                    var container = panel.container;
                    var rect = panel.addNode("rect", {
                        x: "1",
                        y: "1",
                        rx: "30",
                        ry: "30",
                        width: 200,
                        height: 60,
                        "fill": "#fff"
                    });
                    // 线条及文字
                    var line = panel.addNode("path", {
                        "stroke-width": 1,
                        fill: "none",
                        d: "M0 30L200 30",
                        r: 30,
                        id: nodeId + 'l',
                        "stroke": "none"
                    });
                    var txt = panel.addNode("text");
                    var txtPath = panel.addNode("textPath", {
                        "text-anchor": "middle",
                        "baseline-shift": "-4",
                        "startOffset": "50%",
                        "fill": "#000",
                        "stroke": "none"
                    });
                    txtPath.setAttributeNS(xlinkNS, "xlink:href", "#" + nodeId + "l");
                    txtPath.textContent = "结束";
                    txt.appendChild(txtPath);
                    // 包裹
                    var g = panel.addNode("g", {
                        transform: 'matrix(1,0,0,1,' + x + ',' + y + ')',
                        class: "selectable",
                        id: nodeId,
                        code: nodeId,
                        name: "结束",
                        type: "end"
                    });
                    $(g).append(rect, line, txt);
                    var iconSvg = '<svg y="16" x="16" stroke="none"  width="28" height="28" viewBox="0 0 16 16"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#endIcon"></use></svg>'
                    $(iconSvg).appendTo($(g));
                    container.append(g);
                    var ret = {
                        name: "结束",
                        id: "endIns",
                        svg: g,
                        property: {},
                        lineInList: [],
                        lineOutList: [],
                        lines: [],
                        text: "结束",
                        x: x,
                        y: y,
                        original: this
                    };
                    return ret;
                }
            }]
    },
    {
        text: "Task",
        FlowNode: [
            {
                name: "起草节点（Draftnode）",
                id: "draft",
                type: "task",
                icon: "draft",
                width: 201,
                height: 60,
                caption: "起草节点",
                property: ["filter_rule", "auto_pick_rule", "approval_criteria","candidate", "attachment", "form_id", "modnodesnames", "mmodnodesnames"], // [ "处理人","审批意见中上传附件","表单ID", "可修改的节点", "必须修改的节点" ]
                inst: function (x, y, panel, nodeId, prop) {
                    var container = panel.container;
                    var rect = panel.addNode("rect", {
                        x: "1",
                        y: "1",
                        width: 200,
                        height: 60,
                        rx: 4,
                        "fill": "#fff"
                    });
                    // 线条及文字
                    var line = panel.addNode("path", {
                        "stroke-width": 1,
                        fill: "none",
                        d: "M0 30L200 30",
                        r: 30,
                        id: nodeId + 'l',
                        "stroke": "none"
                    });
                    var txt = panel.addNode("text");
                    var txtPath = panel.addNode("textPath", {
                        "text-anchor": "middle",
                        "baseline-shift": "-6",
                        "startOffset": "50%",
                        "fill": "#000",
                        "stroke": "none"
                    });
                    txtPath.setAttributeNS(xlinkNS, "xlink:href", "#" + nodeId + "l");
                    txtPath.textContent = "起草节点";
                    txt.appendChild(txtPath);
                    // 包裹
                    var g = panel.addNode("g", {
                        transform: 'matrix(1,0,0,1,' + x + ',' + y + ')',
                        class: "selectable",
                        id: nodeId,
                        code: nodeId,
                        type: "draftNode",
                        name: "起草节点",
                        operator: "",
                        filter_rule: "",
                        auto_pick_rule: "",
                        approval_criteria: "",
                        candidate: "",
                        candidategroup: "",
                        notice_way: "false,false,false",
                        attachment: "false",
                        notice_draft_man: "0,0,0",
                        form_id: "",
                        can_update_nodes: "",
                        modnodesnames: "",
                        must_update_nodes: "",
                        mmodnodesnames: ""
                    });
                    $(g).append(rect, line, txt);
                    var iconSvg = '<svg y="16" x="16" stroke="none" width="28" height="28" viewBox="0 0 16 16"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#draftIcon"></use></svg>'
                    $(iconSvg).appendTo($(g));
                    container.append(g);
                    var ret = {
                        name: "任务1",
                        id: "blockIns",
                        svg: g,
                        property: {},
                        lineInList: [],
                        lineOutList: [],
                        lines: [],
                        text: "任务1",
                        x: x,
                        y: y,
                        original: this
                    };
                    return ret;
                }
            },
            {
                name: "审批节点（Approve node）",
                id: "block",
                type: "task",
                icon: "task",
                width: 201,
                height: 60,
                caption: "用户任务",
                property: ["modnodesnames", "mmodnodesnames", "null_operator_skip", "double_skip", "circulation_mode", "notice_way",//"处理人", "可修改的节点", "必须修改的节点", "处理人为空跳过", "身份重复跳过", "流转方式", "通知方式",
                    "attachment", "options", "urge_operator", "notice_draft_man", "auto_skip", "form_id", "filter_rule", "auto_pick_rule","approval_criteria","candidate"],//"审批意见中上传附件", "编辑主文档", "操作定义", "操作模板", "自定义操作","催办处理人", "通知起草人", "通知特权人", "自动跳过", "表单ID"
                inst: function (x, y, panel, nodeId, prop) {
                    var container = panel.container;
                    var rect = panel.addNode("rect", {
                        x: "1",
                        y: "1",
                        width: 200,
                        height: 60,
                        rx: 4,
                        "fill": "#fff"
                    });
                    // 线条及文字
                    var line = panel.addNode("path", {
                        "stroke-width": 1,
                        fill: "none",
                        d: "M0 30L200 30",
                        r: 30,
                        id: nodeId + 'l',
                        "stroke": "none"
                    });
                    var txt = panel.addNode("text");
                    var txtPath = panel.addNode("textPath", {
                        "text-anchor": "middle",
                        "baseline-shift": "-6",
                        "startOffset": "50%",
                        "fill": "#000",
                        "stroke": "none"
                    });
                    txtPath.setAttributeNS(xlinkNS, "xlink:href", "#" + nodeId + "l");
                    txtPath.textContent = "审批节点";
                    txt.appendChild(txtPath);
                    // 包裹
                    var g = panel.addNode("g", {
                        transform: 'matrix(1,0,0,1,' + x + ',' + y + ')',
                        class: "selectable",
                        id: nodeId,
                        code: nodeId,
                        type: "approveNode",
                        name: "审批节点",
                        operator: "", // 默认处理人
                        candidate: "",
                        candidategroup: "",
                        communicators: "", // 沟通人
                        null_operator_skip: "false", // 处理人为空跳过
                        double_skip: "false", // 身份重复跳过
                        circulation_mode: "", // 流转方式
                        filter_rule: "", //过滤规则
                        auto_pick_rule: "", // 自动选人规则
                        approval_criteria: "",// 审批基准
                        notice_way: "false,false,false", // 通知方式
                        attachment: "false", // 审批意见中上传附件
                        options: "false,false,false,false,false", // 自定义操作
                        remisable_nodes: "", // 可驳回的节点
                        remisable_nodesnames: "",
                        jumpernodes: "", // 可跳转的节点
                        jumpernodesnames: "",
                        can_update_nodes: "", // 可修改的节点
                        modnodesnames: "",
                        must_update_nodes: "", // 必须修改的节点
                        mmodnodesnames: "",
                        urge_operator: "0,0,0", // 催办处理人
                        notice_draft_man: "0,0,0", // 通知起草人
                        auto_skip: "0,0,0", // 自动跳过
                        form_id: "" // 表单ID
                    });
                    $(g).append(rect, line, txt);
                    var iconSvg = '<svg y="16" x="16" stroke="none" width="28" height="28" viewBox="0 0 16 16"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#taskIcon"></use></svg>';
                    $(iconSvg).appendTo($(g));
                    container.append(g);
                    var ret = {
                        name: "任务1",
                        id: "blockIns",
                        svg: g,
                        property: {},
                        lineInList: [],
                        lineOutList: [],
                        lines: [],
                        text: "任务1",
                        x: x,
                        y: y,
                        original: this
                    };
                    // zNodes.push({ id:nodeId,name:"审批节点", open:true});
                    // $.fn.zTree.init($("#treeDemo"), setting, zNodes);
                    return ret;
                }
            },
            {
                name: "子流程节点（Sub Flow）",
                id: "children",
                type: "task",
                icon: "children",
                width: 201,
                height: 60,
                caption: "用户任务",
                property: ["sub_flow"],//"通知方式"
                inst: function (x, y, panel, nodeId, prop) {
                    var container = panel.container;
                    var rect = panel.addNode("rect", {
                        x: "1",
                        y: "1",
                        width: 200,
                        height: 60,
                        rx: 4,
                        "fill": "#fff"
                    });
                    // 线条及文字
                    var line = panel.addNode("path", {
                        "stroke-width": 1,
                        fill: "none",
                        d: "M0 30L200 30",
                        r: 30,
                        id: nodeId + 'l',
                        "stroke": "none"
                    });
                    var txt = panel.addNode("text");
                    var txtPath = panel.addNode("textPath", {
                        "text-anchor": "middle",
                        "baseline-shift": "-6",
                        "startOffset": "50%",
                        "fill": "#000",
                        "stroke": "none"
                    });
                    txtPath.setAttributeNS(xlinkNS, "xlink:href", "#" + nodeId + "l");
                    txtPath.textContent = "子流程节点";
                    txt.appendChild(txtPath);
                    // 包裹
                    var g = panel.addNode("g", {
                        transform: 'matrix(1,0,0,1,' + x + ',' + y + ')',
                        class: "selectable",
                        id: nodeId,
                        code: nodeId, //节点编号
                        type: "subFlowNode",
                        name: "子流程节点",
                        sub_flow: ""
                    });
                    $(g).append(rect, line, txt);
                    var iconSvg = '<svg y="16" x="16" stroke="none" width="28" height="28" viewBox="0 0 16 16"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#childrenIcon"></use></svg>';
                    $(iconSvg).appendTo($(g));
                    container.append(g);
                    var ret = {
                        name: "任务1",
                        id: "blockIns",
                        svg: g,
                        property: {},
                        lineInList: [],
                        lineOutList: [],
                        lines: [],
                        text: "任务1",
                        x: x,
                        y: y,
                        original: this
                    };
                    // zNodes.push({ id:nodeId,name:"审批节点", open:true});
                    // $.fn.zTree.init($("#treeDemo"), setting, zNodes);
                    return ret;
                }
            },
            {
                name: "通知节点（Noticenode）",
                id: "notice",
                type: "task",
                icon: "notice",
                width: 201,
                height: 60,
                caption: "通知节点",
                property: ["null_operator_skip", "double_skip", "attachment", "form_id", "filter_rule", "auto_pick_rule", "approval_criteria", "candidate", "notice_way"],//[ "处理人", "通知方式" ],
                inst: function (x, y, panel, nodeId, prop) {
                    var container = panel.container;
                    var rect = panel.addNode("rect", {
                        x: "1",
                        y: "1",
                        width: 200,
                        height: 60,
                        rx: 4,
                        "fill": "#fff"
                    });
                    // 线条及文字
                    var line = panel.addNode("path", {
                        "stroke-width": 1,
                        fill: "none",
                        d: "M0 30L200 30",
                        r: 30,
                        id: nodeId + 'l',
                        "stroke": "none"
                    });
                    var txt = panel.addNode("text");
                    var txtPath = panel.addNode("textPath", {
                        "text-anchor": "middle",
                        "baseline-shift": "-6",
                        "startOffset": "50%",
                        "fill": "#000",
                        "stroke": "none"
                    });
                    txtPath.setAttributeNS(xlinkNS, "xlink:href", "#" + nodeId + "l");
                    txtPath.textContent = "通知节点";
                    txt.appendChild(txtPath);
                    // 包裹
                    var g = panel.addNode("g", {
                        transform: 'matrix(1,0,0,1,' + x + ',' + y + ')',
                        class: "selectable",
                        id: nodeId,
                        code: nodeId,
                        type: "noticeNode",
                        name: "通知节点",
                        null_operator_skip: "false",
                        double_skip: "false",
                        attachment: "false",
                        form_id: "",
                        operator: "",
                        filter_rule: "",
                        auto_pick_rule: "",
                        approval_criteria: "",
                        candidate: "",
                        candidategroup: "",
                        notice_way: "false,false,false"
                    });
                    $(g).append(rect, line, txt);
                    var iconSvg = '<svg y="16" x="16" stroke="none" width="28" height="28" viewBox="0 0 1000 1000"><use xmlns:xlink="http://www.w3.org/1999/xlink" xlink:href="#noticeIcon"></use></svg>';
                    $(iconSvg).appendTo($(g));
                    container.append(g);
                    var ret = {
                        name: "通知节点",
                        id: "noticeIns",
                        svg: g,
                        property: {},
                        lineInList: [],
                        lineOutList: [],
                        lines: [],
                        text: "通知节点",
                        x: x,
                        y: y,
                        original: this
                    };
                    return ret;
                }
            }]
    }, {
        text: "Gateways",
        FlowNode: [{
            name: "条件分支（Exclusivegateway）",
            id: "exclusiveG",
            type: "gatewayex",
            icon: "exclusive",
            width: 60,
            height: 60,
            caption: "条件",
            property: [],
            inst: function (x, y, panel, nodeId) {
                var container = panel.container;
                var path = panel.addNode("path", {
                    d: "M0 30  L30 0  L60 30  L30 60 L0 30 M 22 22 L38 38 M38 22 L22 38",
                    "fill-opacity": 0
                }); // 外层菱形
                // 线条及文字
                var line = panel.addNode("path", {
                    "stroke-width": 1,
                    fill: "none",
                    d: "M20 43L40 43",
                    r: 30,
                    id: nodeId + 'l',
                    "stroke": "none"
                });
                var txt = panel.addNode("text");
                var txtPath = panel.addNode("textPath", {
                    "text-anchor": "middle",
                    "baseline-shift": "-6",
                    "startOffset": "50%",
                    "fill": "blue",
                    "font-weight": "600",
                    "stroke": "none"
                });
                txtPath.setAttributeNS(xlinkNS, "xlink:href", "#" + nodeId + "l");
                txtPath.textContent = "";
                txt.appendChild(txtPath);
                // 包裹
                var g = panel.addNode("g", {
                    transform: 'matrix(1,0,0,1,' + x + ',' + y + ')',
                    class: "selectable",
                    id: nodeId,
                    code: nodeId,
                    type: "gatewayex",
                    name: "条件分支"
                });
                $(g).append(path, line, txt);
                container.append(g);
                var ret = {
                    name: "条件分支",
                    id: "ExclusiveGIns",
                    svg: g,
                    property: {},
                    lineInList: [],
                    lineOutList: [],
                    lines: [],
                    text: "条件分支",
                    x: x,
                    y: y,
                    original: this
                };
                return ret;
            }
        }, {
            name: "并行分支（Parallel gateway）",
            id: "parallelG",
            type: "gatewaypa",
            icon: "parallel",
            width: 60,
            height: 60,
            caption: "并行",
            property: [],
            inst: function (x, y, panel, nodeId) {
                var container = panel.container;
                var path = panel.addNode("path", {
                    d: "M0 30  L30 0  L60 30  L30 60 L0 30 M20 30 L40 30 M30 20 L30 40",
                    "fill-opacity": 0
                }); // 外层菱形
                // 线条及文字
                var line = panel.addNode("path", {
                    "stroke-width": 1,
                    fill: "none",
                    d: "M20 45L40 45",
                    r: 30,
                    id: nodeId + 'l',
                    "stroke": "none"
                });
                var txt = panel.addNode("text");
                var txtPath = panel.addNode("textPath", {
                    "text-anchor": "middle",
                    "baseline-shift": "-6",
                    "startOffset": "50%",
                    "fill": "blue",
                    "font-weight": "600",
                    "stroke": "none"
                });
                txtPath.setAttributeNS(xlinkNS, "xlink:href", "#" + nodeId + "l");
                txtPath.textContent = "";
                txt.appendChild(txtPath);
                // 包裹
                var g = panel.addNode("g", {
                    transform: 'matrix(1,0,0,1,' + x + ',' + y + ')',
                    class: "selectable",
                    id: nodeId,
                    code: nodeId,
                    type: "gatewaypa",
                    name: "并行分支"
                });
                $(g).append(path, line, txt);
                container.append(g);
                var ret = {
                    name: "并行分支",
                    id: "parallelGIns",
                    svg: g,
                    property: {},
                    lineInList: [],
                    lineOutList: [],
                    lines: [],
                    text: "并行分支",
                    x: x,
                    y: y,
                    original: this
                };
                return ret;
            }
        }, {
            name: "包含分支（Inclusive gateway）",
            id: "inclusiveG",
            type: "gatewayin",
            icon: "inclusive",
            width: 60,
            height: 60,
            caption: "包含",
            property: [],
            inst: function (x, y, panel, nodeId) {
                var container = panel.container;
                var path = panel.addNode("path", {
                    d: "M0 30  L30 0  L60 30  L30 60 z",
                    "fill-opacity": 0
                }); // 外层菱形
                var circle = panel.addNode("circle", {
                    stroke: "inherit",
                    "fill-opacity": 0,
                    "cx": 30,
                    "cy": 30,
                    "r": 10
                });// 圆
                // 线条及文字
                var line = panel.addNode("path", {
                    "stroke-width": 1,
                    fill: "none",
                    d: "M20 45L40 45",
                    r: 30,
                    id: nodeId + 'l',
                    "stroke": "none"
                });
                var txt = panel.addNode("text");
                var txtPath = panel.addNode("textPath", {
                    "text-anchor": "middle",
                    "baseline-shift": "-6",
                    "startOffset": "50%",
                    "fill": "blue",
                    "font-weight": "600",
                    "stroke": "none"
                });
                txtPath.setAttributeNS(xlinkNS, "xlink:href", "#" + nodeId + "l");
                txtPath.textContent = "";
                txt.appendChild(txtPath);
                // 包裹
                var g = panel.addNode("g", {
                    transform: 'matrix(1,0,0,1,' + x + ',' + y + ')',
                    class: "selectable",
                    id: nodeId,
                    code: nodeId,
                    type: "gatewayin",
                    name: "包含分支"
                });
                $(g).append(path, circle, line, txt);
                container.append(g);
                var ret = {
                    name: "包含分支",
                    id: "inclusiveGIns",
                    svg: g,
                    property: {},
                    lineInList: [],
                    lineOutList: [],
                    lines: [],
                    text: "包含分支",
                    x: x,
                    y: y,
                    original: this
                };
                return ret;
            }
        }]
    }];

function Point(x, y) {
    this.x = x;
    this.y = y;
}

Point.prototype.distance = function (g2) {
    return Math.abs(this.x - g2.x) + Math.abs(this.y - g2.y)
};
Point.prototype.point = function () {
    return this.x + " " + this.y;
};

function Rect(selector) {
    this.selector = selector;
    var self = this;
    this.x = function () {
        var viewBox = designer.designpanel.container[0].getAttribute("viewBox").split(" ");
        var matrix = self.selector.getCTM();
        return matrix.e * zoom + Number(viewBox[0]);
    };
    this.y = function () {
        var viewBox = designer.designpanel.container[0].getAttribute("viewBox").split(" ");
        var matrix = self.selector.getCTM();
        return matrix.f * zoom + Number(viewBox[1]);
    };
    this.width = function () {
        return designer.designpanel.nodeData[self.selector.getAttribute("id")].original.width;
    };
    this.height = function () {
        return designer.designpanel.nodeData[self.selector.getAttribute("id")].original.height;
    };
    this.get = function (x, y) {
        return new Point(x, y);
    };
    this.left = function(){return this.get(this.x(), this.y() + this.height() / 2)};
    this.top = function(){return this.get(this.x() + this.width() / 2, this.y())};
    this.right = function(){return this.get(this.x() + this.width(), this.y() + this.height() / 2)};
    this.bottom = function(){return this.get(this.x() + this.width() / 2, this.y() + this.height())};
    this.point = function () {
        return (this.x()) + " " + (this.y());
    };
}

// 画线
function Line(start, end, designer2) {
    var self = this;
    this.designer = designer2;
    this.start = start;// g
    this.end = end; // g
    this.line;// path
    this.lineData = {
        id: "line",
        property: []
    }
    this.refresh = function () {
        if (!this.line) {
            var nodeId = designer2.getId('line', workflow);
            // 线条及文字
            this.line = designer2.addNode("path", {
                id: nodeId + 'l',
                stroke: "#000",
                "stroke-width": 2,
                "fill-opacity": 0,
                "marker-end": "url(\"#arrow\")"
            });

            this.txt = designer2.addNode("text");
            this.txtPath = designer2.addNode("textPath", {
                "text-anchor": "middle",
                "baseline-shift": "6",
                "startOffset": "50%",
                "fill": "#000",
                "stroke": "none"
            });
            this.txtPath.setAttributeNS(xlinkNS, "xlink:href", "#" + nodeId + 'l');
            this.txtPath.textContent = "";
            this.txt.appendChild(this.txtPath);
            // 包裹
            var g = designer2.addNode("g", {
                class: "selectable",
                id: nodeId,
                name: "",
                type: "line",
                "start": start.id,
                "end": end.id,
                auto_skip: "",
                count: "",
                condition_exps: ""
            });
            $(g).append(this.line, this.txt);
            designer2.container.append(g);
            designer2.nodeData[nodeId] = this;
            $(this.line).contextmenu(function (e) {
                e.preventDefault();
            });
            $(this.line).click(function () {
                self.lineData.property = ["name", "start_direction", "end_direction"];
                // 取消节点实例选中状态
                $.each(designer2.container.find(".selected,._active"), function (index, item) {
                    item.classList.remove("selected", "_active");
                });
                designer2.nodeinstance.splice(0, designer2.nodeinstance.length);
                // 匹配排他网关连出线条属性
                var str = "gatewayex";
                if (self.start.id.indexOf(str) !== -1) {
                    self.lineData.property = ["name", "start_direction", "end_direction"];
                    self.lineData.property.push("condition_exps");
                }
                // 匹配融合网关连出线条属性
                var str2 = "gatewayin";
                if (self.start.id.indexOf(str2) !== -1) {
                    var line_out = designer2.nodeData[self.start.id].lineOutList;
                    if (line_out.length > 1) {//连出线大于1才提示消息
                        self.lineData.property = ["name"];
                        self.lineData.property.push("condition_exps", "count");
                    }
                }
                this.classList.add("_active");
                designer.propertypanel.init(self.lineData, nodeId);
                $(".content").eq(0).show();// 第一个默认显示
                $(".u-property [data-toggle='title']").eq(0).addClass("icon-minus");// 第一个默认显示
                // 融合网关排序
                var j = 1;
                $('#design g[type="line"]').each(function (index, elem) {
                    var startStr = this.getAttribute("start");
                    var changeNum = this.getAttribute("auto_skip");
                    if (startStr.indexOf(str2) !== -1 && changeNum == "") {
                        this.setAttribute('count', j);
                        $('#' + elem.id + 'line3').val(j);
                        j += 1;
                    }
                    if (changeNum.length > 0) {
                        this.setAttribute('count', changeNum);
                    }
                });
            });
        }
        var rectstart = new Rect(start);
        var rectend = new Rect(end);
        this.line.setAttribute("d", rectstart.drawg(rectend, this.line.parentNode.getAttribute("start_direction"), this.line.parentNode.getAttribute("end_direction")));
        return this;
    }
}

// 设置线的连接
Rect.prototype.drawg = function (g2, sdir, tdir) {
    var d;
    if (sdir != null && tdir != null && sdir != 0 && tdir != 0) {
        var dir1 = new Direction(sdir);
        var dir2 = new Direction(tdir);
        if (dir1.test(dir2)) {//180度
            return dir1.draw180Line(this[dir1.direction], g2[dir2.direction]);
        } else if (dir1.next().test(dir2) || dir1.previous().test(dir2)) {
            return dir1.drawRightAngle(this[dir1.direction], g2[dir2.direction]);
        } else if (dir1.opposite().test(dir2)) {
            return dir1.draw0Line(this[dir1.direction], g2[dir2.direction]);
        }
    }

    // 开始判断直联
    if (this.left().y == g2.right().y && this.left().x > g2.right().x) {
        return "M" + this.left().point() + " L" + g2.right().point();
    } else if (this.right().y == g2.left().y && this.right().x < g2.left().x) {
        return "M" + this.right().point() + " L" + g2.left().point();
    } else if (this.top().x == g2.bottom().x && this.top().y > g2.bottom().y) {
        return "M" + this.top().point() + " L" + g2.bottom().point();
    } else if (this.bottom().x == g2.top().x && this.bottom().y < g2.top().y) {
        return "M" + this.bottom().point() + " L" + g2.top().point();
    }
    // 转角，只有一个九十度
    var dir = new Direction();
    var i = 0;
    var distance = null;
    do {
        i++;
        if (dir.isDir(this[dir.direction](), g2[dir.next().direction]()) && dir.next().isDir(g2[dir.next().direction](), this[dir.direction]())) {
            var tmpDistance = this[dir.direction]().distance(g2[dir.next().direction]());
            if (!distance || distance > tmpDistance) {
                d = dir.drawRightAngle(this[dir.direction](), g2[dir.next().direction]());
                distance = tmpDistance;
            }
        } else if (dir.isDir(this[dir.direction](), g2[dir.previous().direction]()) && dir.previous().isDir(g2[dir.previous().direction](), this[dir.direction]())) {
            var tmpDistance = this[dir.direction]().distance(g2[dir.previous().direction]());
            if (!distance || distance > tmpDistance) {
                d = dir.drawRightAngle(this[dir.direction](), g2[dir.previous().direction]());
                distance = tmpDistance;
            }
        }
        dir = dir.next();
    } while (i < 4);
    if (distance)
        return d;

    i = 0;
    do { // 两转角
        var source = this[dir.direction]();
        var target = g2[dir.direction]();
        if (dir.next().isDir(source, target) || dir.previous().isDir(source, target)) { // 同向
            var tmpDistance = source.distance(target);
            if (!distance || distance > tmpDistance) {
                d = dir.draw180Line(source, target);
                distance = tmpDistance;
            }
        }
        target = g2[dir.opposite().direction]();
        if (dir.isDir(source, target)) // 反向
            var tmpDistance = source.distance(target);
        if (!distance || distance > tmpDistance) {
            d = dir.draw0Line(source, target);
            distance = tmpDistance;
        }
        i++;
        dir = dir.next();
    } while (i < 4);

    if (distance)
        return d;
    return "M" + this.right.point() + " L" + g2.top.point();
};

// ==========方向类===
function Direction(direction) {
    this.direction = direction || "right";
    this.minSize = 40;//最短的线长度
}

Direction.prototype.test = function (dir) {
    return dir.direction == this.direction;
};
Direction.prototype.previous = function () {
    switch (this.direction) {
        case "right":
            return new Direction("top");
        case "top":
            return new Direction("left");
        case "left":
            return new Direction("bottom");
        case "bottom":
            return new Direction("right");
    }
};
Direction.prototype.next = function () {
    switch (this.direction) {
        case "right":
            return new Direction("bottom");
        case "top":
            return new Direction("right");
        case "left":
            return new Direction("top");
        case "bottom":
            return new Direction("left");
    }
};
Direction.prototype.opposite = function () {
    switch (this.direction) {
        case "right":
            return new Direction("left");
        case "top":
            return new Direction("bottom");
        case "left":
            return new Direction("right");
        case "bottom":
            return new Direction("top");
    }
};

Direction.prototype.isDir = function (p1, p2) {
    switch (this.direction) {
        case "right":
            return p2.x > p1.x;
        case "top":
            return p2.y < p1.y;
        case "left":
            return p2.x < p1.x;
        case "bottom":
            return p2.y > p1.y;
    }
};
/**
 * 连接两点，转角一次角
 */
Direction.prototype.drawRightAngle = function (p1, p2) {
    var arr = new Array();
    var token;
    arr.push(p1.point());
    switch (this.direction) {
        case "right":
            token = new Point(p2.x, p1.y);
            break;
        case "top":
            token = new Point(p1.x, p2.y);
            break;
        case "left":
            token = new Point(p2.x, p1.y);
            break;
        case "bottom":
            token = new Point(p1.x, p2.y);
            break;
    }
    arr.push(token.point());
    arr.push(p2.point());
    return "M" + arr[0] + " L" + arr[1] + " L" + arr[2];
};
/**
 * 连接两点，转角两次角，180度 ─────┐ │ │ ─────┘
 */
Direction.prototype.draw180Line = function (p1, p2) {
    var arr = new Array();
    var token;
    arr.push(p1.point());
    switch (this.direction) {
        case "right":
            token = new Point(Math.max(p2.x, p1.x) + this.minSize, p1.y);
            break;
        case "top":
            token = new Point(p1.x, Math.min(p2.y, p1.y) - this.minSize);
            break;
        case "left":
            token = new Point(Math.min(p2.x, p1.x) - this.minSize, p1.y);
            break;
        case "bottom":
            token = new Point(p1.x, Math.max(p2.y, p1.y) + this.minSize);
            break;
    }
    arr.push(token.point());
    switch (this.direction) {
        case "left":
        case "right":
            token = new Point(token.x, p2.y);
            break;
        case "bottom":
        case "top":
            token = new Point(p2.x, token.y);
            break;
    }
    arr.push(token.point());
    arr.push(p2.point());

    return "M" + arr[0] + " L" + arr[1] + " L" + arr[2] + " L" + arr[3];
};
/**
 * 连接两点，转角两次角，方向不变度 ─────┐ │ │ └───────
 */
Direction.prototype.draw0Line = function (p1, p2) {
    var arr = new Array();
    var token;
    arr.push(p1.point());
    switch (this.direction) {
        case "left":
        case "right":
            token = new Point((p2.x + p1.x) / 2, p1.y);
            break;
        case "top":
        case "bottom":
            token = new Point(p1.x, (p2.y + p1.y) / 2);
            break;
    }
    arr.push(token.point());
    switch (this.direction) {
        case "left":
        case "right":
            token = new Point(token.x, p2.y);
            break;
        case "bottom":
        case "top":
            token = new Point(p2.x, token.y);
            break;
    }
    arr.push(token.point());
    arr.push(p2.point());
    return "M" + arr[0] + " L" + arr[1] + " L" + arr[2] + " L" + arr[3];
};

function ScaleObject(element) {
    this.element = element;
    this.rect = new Rect(element[0]);
    this.drag = false;
    this.gap = 5;
    this.lastPos = null;
    var self = this;
    var opt = {
        mousedown: function (event) {
            self.drag = true;
            self.lastPos = [event.offsetX, event.offsetY];
        },
        mouseup: function (event) {
            self.drag = false;
            self.lastPos = null;
        },
        mousemove: function (event) {
            if (self.drag && self.lastPos) {

            } else {
                var x = 0;
                if (event.offsetX - self.rect.x() < self.gap)
                    x += 1;
                if (event.offsetY - self.rect.y() < self.gap)
                    x += 4;
                if (self.rect.x() + self.rect.width() - event.offsetX < self.gap)
                    x += 2;
                if (self.rect.y() + self.rect.height() - event.offsetY < self.gap)
                    x += 8;
                var map = {
                    0: "pointer",
                    1: "w-resize",
                    2: "e-resize",
                    4: "n-resize",
                    8: "s-resize",
                    5: "nw-resize",
                    9: "sw-resize",
                    6: "ne-resize",
                    10: "nw-resize"
                };
                $(self.element).css("cursor", map[x]);
            }
        }
    };
    element.on(opt);
};